#ifndef xpack_utils_unique_array
#define xpack_utils_unique_array
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_unique_array::inc
#include"adapter/random_access.hpp"
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"macro/xis_nullptr.hpp"
#include"macro/xnew.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_unique_array{
    template<class item_t>
    struct free{
        constexpr free(){}

        void operator()(item_t * mem, uxx length, auto){
            inc::memory::default_free<item_t>(mem, length);
        }
    };

    template<class itemx_t, class free_t = free<itemx_t>>
    xstruct(
        xtmpl(unique_array, itemx_t, free_t),
        xpubb(inc::random_access<unique_array<itemx_t, free_t>, itemx_t>),
        xpubb(inc::disable_copy),
        xprif(m_ptr,                    itemx_t *),
        xpric(m_length,                 sizeof(uxx) * 8 - 3, uxx),
        xpric(m_is_requires_destruction,1, uxx),
        xpric(m_is_requires_free,       1, uxx),
        xpric(m_addition_bit,           1, uxx)
    )
        using final_t                   = the_t;
        using item_t                    = itemx_t;

    public:
        xprops()
            xpubget(length, uxx);
            xpubget(is_requires_destruction, bool);
            xpubget(is_requires_free, bool);
            xpubget(addition_bit, bool);
        $

        xprops_operator()

    public:
        /**
         * @brief 
         * 默认初始化，指向 nullptr
         */
        unique_array(decltype(nullptr) = nullptr) : 
            unique_array(nullptr, ::length{0}, not need_destruction, not need_free) {}

        /**
         * @brief 
         * 初始化
         * @param ptr 托管的内存
         * @param length 元素长度
         * @param need_destruction 是否在当前对象析构时顺带析构托管的内存 ptr
         * @param need_free 是否释放托管的内存
         * @param addition_bit 附加信息的位
         */
        unique_array(
            item_t            * ptr, 
            ::length            length,
            need_destruction_t  need_destruction, 
            need_free_t         need_free,
            generic_option_t    addition_bit = generic_option_t(false)
        ) :
            m_ptr(ptr),
            m_length(length),
            m_is_requires_destruction(need_destruction),
            m_is_requires_free(need_free),
            m_addition_bit(addition_bit){
        }

        /**
         * @brief
         * 剥夺 value 对托管内存的所有权
         * @param value 
         */
        unique_array(the_t && value) :
            unique_array(
                value.m_ptr, 
                ::length(value.m_length), 
                need_destruction_t((bool)value.m_is_requires_destruction),
                need_free_t((bool)value.m_is_requires_free),
                generic_option_t((bool)value.m_addition_bit)
            ){
            value.m_is_requires_destruction    = false;
            value.m_is_requires_free           = false;
        }

        ~unique_array(){
            *this                       = nullptr;
        }

        /**
         * @brief 
         * 准备转交所有权，转交后当前对象将不能再访问托管的内存
         * @return the_t&& 
         */
        the_t && hand_over() const {
            return (the_t &&)*this;
        }

        /**
         * @brief 
         * 借用当前对象托管内存的指针
         * @note
         * 接纳该返回值的对象不具有托管内存的所有权
         * 该内存的生命周期与所有者的生命周期一致，如果当前对象析构，
         * 并且未通过 hand_over 接口转交所有权给更长生命周期的对象，
         * 那么原来通过 lend 接口借用的指针将失效
         * @return item_t* 
         */
        item_t * lend() const {
            return m_ptr;
        }

        the_t & operator=(the_t && value){
            if (value.m_ptr == m_ptr){
                return *this;
            }

            *this                       = nullptr;
            xnew (this) the_t((the_t &&)value);
            return *this;
        }

        the_t & operator=(decltype(nullptr)) {
            if (m_is_requires_destruction){
                m_is_requires_destruction   = false;

                for(uxx i = 0; i < m_length; i++){
                    m_ptr[i].~item_t();
                }
            }

            if (m_is_requires_free){
                m_is_requires_free          = false;
                free_t()(m_ptr, m_length, this);
            }

            m_length                    = 0;
            m_ptr                       = nullptr;
            return *this;
        }

        xis_nullptr(
            m_ptr == nullptr
        )

    private:
        friend inc::random_access<the_t, item_t>;

        item_t & random_get(uxx i) const {
            return m_ptr[i];
        }
    $
}

namespace mixc::utils_unique_array::origin{
    using mixc::utils_unique_array::unique_array;
}

#endif

xexport_space(mixc::utils_unique_array::origin)
